package com.example.study.jetpack.hilt

/**
 *  created by 20300
 *   on 2022/3/17
 *   describe:https://developer.android.google.cn/training/dependency-injection?hl=zh_cn
 */
class hilt官网 {
    /*概览
    依赖注入(DI)是一种广泛用于编程的技术,非常适用于Android开发.遵循DI的原则可以为良好的应用架构尊定基础
    实现依赖项注入的优势
        `重用代码
        `易于重构
        `易于测试

什么是依赖项注入?
类通常需要引用其他类.例如Car类可能需要引用Engine类.这些类称为依赖项,在此示例中,Car类依赖与拥有Engine类的一个实例
才能运行.
类可通过以下三种方式获取到所需的对象:
1.类构造其所需的依赖项.在以上示例中,Car将创建并初始化自己的Engine实例
2.从其他地方抓取.某些AndroidAPI(如Context getter和getSystemService())的工作原理便是如此
3.以参数形式提供.应用可以在构造类时提供这些依赖项,或者将这些依赖项传入需要各个依赖项的函数,
在以上示例中,Car构造函数将接受接收Engine作为参数

依赖:
apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'

classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'
 implementation "com.google.dagger:hilt-android:2.28-alpha"
    kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"

Hilt应用类
所有使用Hilt的应用都必须包含一个带有@HiltAndroidApp注释的Application类
@HiltAndroidApp会触发Hilt的代码生成操作,生成的代码包括应用的一个基类,该基类充当应用级依赖项容器.

@HiltAndroidApp
class ExampleApplication : Application() { ... }

Hilt目前支持以下Android类:
`Application(通过使用@HiltAndroidApp)
`Activity
`fragment
`View
`Service
`BroadcastReceiver

如果你使用@AndroidEntryPoint为某个Android类添加注释,则还必须为依赖于该类的Android类
添加注释.例如如果为某个Fragment添加注释,则还必须为使用该Fragment的所有Activity添加注释

注意
在Hilt对Android类的支持方面还要注意以下几点:
    Hilt仅支持扩展ComposeActivity的Activity如AppCompatActivity
    Hilt仅支持扩展Androidx.Fragment的Fragment
    Hilt不支持保留的Fragment

@AndroidEntryPoint会为项目中的每个Android类生成一个单独的Hilt组件.
这些组件可以从它们各自父类接收依赖项,如组件层次结构中所述.

如需从组件获取依赖项,请使用@Inject注释执行字段注入:
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {

  @Inject lateinit var analytics: AnalyticsAdapter
  ...
}
注意:由hilt注入的字段不能为私有字段.尝试使用Hilt注入西游字段会导致编译错误.
Hilt注入的类可以有同样使用注入的其他基类.如果这些类是抽象类,则它们不需要@AndroidEntrypoint注释

定义Hilt绑定
为了执行字段注入,Hilt需要知道如何从相应组件提供不要依赖项的实例.
"绑定"包含将某个类型的实例作为依赖项提供所需的信息.
向Hilt提供绑定信息的一种方法是构造函数注入.在某个类的构造函数中使用@Inject注释,
以告知Hilt如何提供该类的实例:
class AnalyticsAdapter @Inject constructor(
  private val service: AnalyticsService
) { ... }
在一个类的代码中,带有注释的构造函数的参数即是该类的依赖项.在本例中,
AnalyticsService是AnalyticsAdapter的一个依赖项.因此,hilt还必须知道如何提供
AnalyticsService的实例

注意:在构建时,Hilt会为Android类生成Dagger组件.然后,Dagger会走查你的代码,并执行以下步骤:
`构建并验证依赖关系图,确保没有为满足依赖关系且没有依赖循环
`生成它在运行时用来创建实际对象及其依赖项的类

Hilt模块
有时,类型不能通过构造函数注入.发生这种情况可能有多种原因.例如,你不能通过构造函数注入不归你
所有的类型,如来自外部库的类.在这些情况下,你可以使用Hilt模块向Hilt提供绑定信息

Hilt模块是一个带有@Module注释的类。与Dagger模块一样，它会告知Hilt如何提供某些
类型的实例。与Dagger模块不同的是，你必须使用@InstallIn为Hilt模块添加注释
以告知Hilt每个模块将用在或安装在哪个Android类中。
    注意:Hilt模块与Gradle模块不同
你在hilt模块中提供的依赖项可以在生成的所有与Hilt模块安装到的Android类关联的组件中使用
    注意:由于Hilt的代码生成操作需要访问使用Hilt的所有Gradle模块,因此编译Application类的Gradle模块
    还需要在其传递依赖项中包含你的所有Hilt模块和通过构造函数注入的类

使用@Binds注入接口实例
以AnalyticsService为例.如果AnalyticsService是一个接口,则你无法通过构造函数注入它,
而应向Hilt提供绑定信息,方法是在Hilt模块内创建一个带有@Binds注释的抽象函数

@Binds注释会告知Hilt在需要提供接口的实例时要使用那种实现
带有注释的函数会向Hilt提供以下信息:
`函数返回类型会告知Hilt函数提供哪个结构的实例.
`函数参数会告知Hilt要提供哪种实现.
interface AnalyticsService {
  fun analyticsMethods()
}

// Constructor-injected, because Hilt needs to know how to
// provide instances of AnalyticsServiceImpl, too.
class AnalyticsServiceImpl @Inject constructor(
  ...
) : AnalyticsService { ... }

@Module
@InstallIn(ActivityComponent::class)
abstract class AnalyticsModule {

  @Binds
  abstract fun bindAnalyticsService(
    analyticsServiceImpl: AnalyticsServiceImpl
  ): AnalyticsService
}

Hilt模块AnalyticsModule带有@InstallIn(ActivityComponent::Class)注释,
因为你希望Hilt将该依赖项注入ExampleActivity.此注释意味着,
AnalyticsModule中所有依赖项都可以在应用的所有Activity中使用

@provides注入实例
接口不是无法通过构造函数注入类型的唯一一种情况.如果某个类,不归你所有(因为它来自外部库,如Retrofit,
okhttpClient或Room数据库等类),或者必须使用构建器模式创建实例,也无法通过构造函数注入

接着前面的例子来讲,如果AnalyticsService类不直接归你所有,
你可以告知Hilt如何提供此类型的实例,方法是在Hilt模块内创建一个函数,
并使用@Provides为该函数添加注释.

带有注释的函数会向Hilt提供以下信息:
`函数返回类型会导致Hilt函数提供哪个类型的实例.
`函数参数会告知Hilt相应类型的依赖项
`函数主体会告知Hilt如何提供相应类型的实例.每当需要提供该类型的实例时,Hilt都会执行函数主体.
@Module
@InstallIn(ActivityComponent::class)
object AnalyticsModule {

  @Provides
  fun provideAnalyticsService(
    // Potential dependencies of this type
  ): AnalyticsService {
      return Retrofit.Builder()
               .baseUrl("https://example.com")
               .build()
               .create(AnalyticsService::class.java)
  }
}

    */
}